#ifndef _PROCESSOR_INFO_H_
#define _PROCESSOR_INFO_H_
#include "types.h"
#include <string>

class ProcessorInfo {
public:
    ProcessorInfo() : _tableVersion(0), _length(0), _processorType(0), _processorFamily(0), _processorID{0, 0}, _voltage(0),
                      _externalClock(0), _maxSpeed(0), _currentSpeed(0), _status(0), _processorUpgrade(0),
                      _L1CacheHandle(0), _L2CacheHandle(0), _L3CacheHandle(0), _coreCount(0), _coreEnabled(0),
                      _threadCount(0), _processorCharacteristics(0), _processorFamily2(0), _coreCount2(0), 
                      _coreEnabled2(0), _threadCount2(0), _threadEnabled(0){}
    void        setVersion(UINT16 ver) { _tableVersion = ver; }
    void        setGeneral(UINT8 len, const std::string& socketDesignation, UINT8 cpuType, UINT8 cpuFamily,
                           const std::string& cpuManufacturer, UINT64 cpuID, const std::string& cpuVersion,
                           UINT8 voltage, UINT16 externalClock, UINT16 maxSpeed, UINT16 curSpeed, 
                           UINT8 status, UINT8 cpuUpgrade);
    void        set2_1(UINT16 l1, UINT16 l2, UINT16 l3);
    void        set2_3(const std::string &sn, const std::string &tag, const std::string &pn);
    void        set2_5(UINT8 coreCount, UINT8 coreEnable, UINT8 threadCount, UINT16 characteristics);
    void        setProcessorFamily2(UINT16 family2) { _processorFamily2 = family2; }
    void        set3_0(UINT16 coreCount2, UINT16 coreEnabled2, UINT16 threadCount2);
    void        setThreadEnabled(UINT16 enabled) { _threadEnabled = enabled; }
    void        setSocketType(const std::string &socketType) { _socketType = socketType; }

    void        print();

private:
    const char *getProcessorType();
    const char *getProcessorFamily();
    const char *getProcessorStatus(UINT8 code);
    const char *getProcessorUpgrade();
    void        printProcessorId();
    void        printProcessorVoltage();
    void        printProcessorFrequency(const char *attr, UINT16 code);
    void        printCpuid(const char *label, enum cpuidType sig, const UINT8 *p);
    void        printProcessorCache(const char *attr, UINT16 code, const char *level, UINT16 ver);
    void        printProcessorCharacteristics();
    enum cpuidType getCpuidType();

private:
    UINT16      _tableVersion;
    // 2.0+
    UINT8       _length;
    std::string _socketDesignation;     // String number for Reference Designation. EXAMPLE: ‘J202’,0
    UINT8       _processorType;
    UINT8       _processorFamily;
    std::string _processorManufacturer; // String number of Processor Manufacturer
    UINT64      _processorID;           // Raw processor identification data
    std::string _processorVersion;      // String number describing the Processor
    UINT8       _voltage;
    UINT16      _externalClock;         // External Clock Frequency, in MHz. If the value is unknown, the field is set to 0.
    UINT16      _maxSpeed;              // Maximum processor speed (in MHz) supported
    UINT16      _currentSpeed;          // Same format as Max Speed
    UINT8       _status;
    UINT8       _processorUpgrade;
    // 2.1+
    UINT16      _L1CacheHandle;
    UINT16      _L2CacheHandle;
    UINT16      _L3CacheHandle;
    // 2.3+
    std::string _serialNumber;
    std::string _assetTag;
    std::string _partNumber;
    // 2.5+
    UINT8       _coreCount;                 // Number of cores per processor socket
    UINT8       _coreEnabled;
    UINT8       _threadCount;
    UINT16      _processorCharacteristics;  // Defines which functions the processor supports
    // 2.6+
    UINT16      _processorFamily2;
    // 3.0+
    UINT16      _coreCount2;
    UINT16      _coreEnabled2;
    UINT16      _threadCount2;
    // 3.6+
    UINT16      _threadEnabled;
    // 3.8+
    std::string _socketType;
};

#endif